module Trivia (Trivia, nuevaT, keywordsT, preguntasT, participantesT, ganadoresT,
proxPreguntaParticipanteT, puntajeAcumuladoT, registrarJugadorT, desregistrarJugadorT,
procesarRespuestaT, usuariosEficientesT, posicionEnT, palabrasRecurrentesT)

where

import Tipos
import SMS
import Pregunta

data Trivia = CrearT [Keyword] [Pregunta] | Jugar Usuario Texto Trivia deriving (Show)

-- Funciones generales -- 

nuevaT :: [Keyword] -> [Pregunta] -> Trivia
nuevaT keywords preguntas = CrearT keywords preguntas

keywordsT :: Trivia -> [Keyword]
keywordsT (CrearT keywords _) = keywords
keywordsT (Jugar _ _ trivia) = keywordsT trivia

preguntasT :: Trivia -> [Pregunta]
preguntasT (CrearT _ preguntas) = preguntas
preguntasT (Jugar _ _ trivia) = preguntasT trivia

participantesT :: Trivia -> [Usuario]
participantesT (CrearT _ _) = []
participantesT (Jugar usuario _ trivia) = sacarRepetidos
        (usuario : (participantesT trivia))

-- Fin funciones generales --

-- GanadoresT -- 

ganadoresT :: Trivia -> [Usuario]
ganadoresT (CrearT _ _) = []
ganadoresT (Jugar usuario texto trivia)
        | ganadoresTAux (Jugar usuario texto trivia) usuario =
                (ganadoresT trivia) ++ [usuario]
        | otherwise = ganadoresT trivia

ganadoresTAux :: Trivia -> Usuario -> Bool
ganadoresTAux (CrearT _ _) _ = False
ganadoresTAux trivia usuarioCandidato =
        (respuestasEnviadas trivia usuarioCandidato == length (preguntasT trivia) + 1)

respuestasEnviadas :: Trivia -> Usuario -> Int
respuestasEnviadas (CrearT _ _) _ = 0
respuestasEnviadas (Jugar usuario _ trivia) usuarioCandidato
        | usuario == usuarioCandidato = 1 + respuestasEnviadas trivia usuarioCandidato
        | otherwise = respuestasEnviadas trivia usuarioCandidato

-- Fin GanadoresT-- 
-- Proxima Pregunta --

proxPreguntaParticipanteT :: Trivia -> Usuario -> Pregunta
proxPreguntaParticipanteT trivia usuario = preguntasT trivia !!
        ((respuestasEnviadas trivia usuario)-1)

-- Fin Proxima Pregunta --

-- PuntajeAcumuladoT -- 

puntajeAcumuladoT :: Trivia -> Usuario -> Puntaje
puntajeAcumuladoT trivia usuario = calcularPuntaje (preguntasT trivia)
        (tail (mensajesDe trivia usuario))

calcularPuntaje :: [Pregunta] -> [Texto] -> Puntaje
calcularPuntaje [] _ = 0
calcularPuntaje _ [] = 0
calcularPuntaje (x:xs) (y:ys) | rtaCorrectaP x == (sacarPalabra y) =
        (puntajeP x) + (calcularPuntaje xs ys)
                              | otherwise = calcularPuntaje xs ys
                     
mensajesDe :: Trivia -> Usuario -> [Texto]
mensajesDe (CrearT _ _) _ = []
mensajesDe (Jugar usuario texto trivia) usuarioSelec | usuario == usuarioSelec =
        (mensajesDe trivia usuarioSelec) ++ [texto]
                                                     | otherwise =
        mensajesDe trivia usuarioSelec 

-- Fin PuntajeAcumuladoT -- 

-- registrarJugadorT -- 

registrarJugadorT :: Trivia -> Usuario -> Keyword -> (Trivia,SMS)
registrarJugadorT trivia usuario keyword = ((Jugar usuario keyword trivia), 
        nuevoSMS usuario ("Hola, tenes 0 puntos. " ++
                primeraPregunta trivia usuario keyword))

primeraPregunta :: Trivia -> Usuario -> Keyword -> Texto
primeraPregunta trivia usuario keyword = 
        textoP (proxPreguntaParticipanteT(Jugar usuario keyword trivia) usuario)

-- Fin registrarJugadorT -- 

-- desregistrarJugadorT -- 

desregistrarJugadorT:: Trivia -> Usuario -> Trivia
desregistrarJugadorT (CrearT keyword pregunta) _ = (CrearT keyword pregunta)
desregistrarJugadorT (Jugar usuarioT texto trivia) usuario | usuario == usuarioT =
        desregistrarJugadorT trivia usuario
                                                           | otherwise =
        (Jugar usuarioT texto (desregistrarJugadorT trivia usuario))
                                                                                                           
-- Fin desregistrarJugadorT -- 

-- procesarRespuestaT -- 

procesarRespuestaT :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
procesarRespuestaT trivia usuario texto
        | esGanador trivia usuario = respuestaGanador trivia usuario
        | esUltima trivia usuario = respuestaUltima trivia usuario texto
        | esCorrecta texto (proxPreguntaParticipanteT trivia usuario) =
                respuestaDeCorrecta trivia usuario texto
        | otherwise = respuestaDeIncorrecta trivia usuario texto 

respuestaGanador :: Trivia -> Usuario -> (Trivia,SMS)
respuestaGanador trivia usuario = (trivia, nuevoSMS usuario
        "Gracias por seguir pagando, pero el juego termino.")

respuestaUltima :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaUltima trivia usuario texto = (Jugar usuario texto trivia, nuevoSMS usuario
        (textoUltima trivia usuario texto))
textoUltima :: Trivia -> Usuario -> Texto -> Texto
textoUltima trivia usuario texto = "Has respondido todas las preguntas. " ++
        (tusPuntos usuario texto trivia)

respuestaDeCorrecta :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaDeCorrecta trivia usuario texto = ((Jugar usuario texto trivia),
        (nuevoSMS usuario ("Bien! " ++ textoDeRespuestaCI trivia usuario texto)))

respuestaDeIncorrecta :: Trivia -> Usuario -> Texto -> (Trivia,SMS)
respuestaDeIncorrecta trivia usuario texto = ((Jugar usuario texto trivia),
        (nuevoSMS usuario ("Mal! " ++ textoDeRespuestaCI trivia usuario texto)))

textoDeRespuestaCI :: Trivia -> Usuario -> Texto -> Texto
textoDeRespuestaCI trivia usuario texto = (tusPuntos usuario texto trivia) ++ " " ++
        textoP(proxPreguntaParticipanteT (Jugar usuario texto trivia) usuario)

esGanador :: Trivia -> Usuario -> Bool
esGanador (CrearT _ _) _ = False
esGanador trivia usuarioCandidato =
        (respuestasEnviadas trivia usuarioCandidato >= length (preguntasT trivia) + 1)

esCorrecta :: Texto -> Pregunta -> Bool
esCorrecta texto proximaPregunta =
        (palabras (sacarPalabra texto)) == (palabras (rtaCorrectaP proximaPregunta))

esUltima :: Trivia -> Usuario -> Bool
esUltima trivia usuario = (textoP (proxPreguntaParticipanteT trivia usuario) ==
        textoP ((preguntasT trivia) !! ((length (preguntasT trivia))-1)))

tusPuntos :: Usuario -> String -> Trivia -> String
tusPuntos usuario texto trivia = "Tenes " ++
        intToString (puntajeAcumuladoT (Jugar usuario texto trivia) usuario) ++ " ptos."

-- Fin procesarRespuestaT -- 

-- UsuariosEficientesT -- 

usuariosEficientesT :: Trivia -> [Usuario]
usuariosEficientesT trivia = losDeMenosParticipaciones trivia
        (losDeMaximoPuntaje trivia (participantesT trivia))

losDeMaximoPuntaje :: Trivia -> [Usuario] -> [Usuario]
losDeMaximoPuntaje _ [] = []
losDeMaximoPuntaje trivia (x:xs)
        | (puntajeAcumuladoT trivia x) == (maximoPuntaje trivia) =
                x : (losDeMaximoPuntaje trivia xs)
        | otherwise = losDeMaximoPuntaje trivia xs
                                 
maximoPuntaje :: Trivia -> Int
maximoPuntaje trivia = maximo (puntajeDeTodos trivia (participantesT trivia))

puntajeDeTodos :: Trivia -> [Usuario] -> [Int]
puntajeDeTodos _ [] = []
puntajeDeTodos trivia (x:xs) = (puntajeAcumuladoT trivia x):(puntajeDeTodos trivia xs)

maximo :: [Int] -> Int
maximo [x] = x
maximo (x:xs) | esMayorOIgualQueTodos x xs = x
              | otherwise = maximo xs
      
esMayorOIgualQueTodos :: Int -> [Int] -> Bool
esMayorOIgualQueTodos x [] = True
esMayorOIgualQueTodos x (y:xs) = (x >= y) && (esMayorOIgualQueTodos x xs)

losDeMenosParticipaciones :: Trivia -> [Usuario] -> [Usuario]
losDeMenosParticipaciones trivia [] = []
losDeMenosParticipaciones trivia (x:xs)
        | respuestasEnviadas trivia x == minimo (participacionesDeTodos trivia (x:xs)) =
                x:(losDeMenosParticipaciones trivia xs)
        | otherwise = losDeMenosParticipaciones trivia xs
                                        
participacionesDeTodos :: Trivia -> [Usuario] -> [Int]
participacionesDeTodos _ [] = []
participacionesDeTodos trivia (x:xs) =
        (respuestasEnviadas trivia x) : (participacionesDeTodos trivia xs)                                        
                                        
minimo :: [Int] -> Int
minimo [x] = x
minimo (x:xs) |esMenorOIgualQueTodos x xs = x
              |otherwise = minimo xs
                          
esMenorOIgualQueTodos :: Int -> [Int] -> Bool
esMenorOIgualQueTodos x [] = True
esMenorOIgualQueTodos x (y:xs) = (x <= y) && (esMenorOIgualQueTodos x xs)

-- Fin UsuariosEficientesT -- 

-- posicionEnT --  

posicionEnT :: Trivia -> Usuario -> Int
posicionEnT trivia usuario | usuario `elem` (ganadoresT trivia) =
        indice usuario (ganadoresT trivia)
                           | otherwise =
        length (ganadoresT trivia) +
        length (participantesConMasPuntosQue trivia usuario (participantesT trivia))

participantesConMasPuntosQue :: Trivia -> Usuario -> [Usuario] -> [Usuario]
participantesConMasPuntosQue _ _ [] = []
participantesConMasPuntosQue trivia usuario (x:xs)
        | noGanadorConMasPuntaje trivia usuario x =
                x : (participantesConMasPuntosQue trivia usuario xs)
        | otherwise = participantesConMasPuntosQue trivia usuario xs

noGanadorConMasPuntaje :: Trivia -> Usuario -> Usuario -> Bool
noGanadorConMasPuntaje trivia usuario noG = not(noG `elem` (ganadoresT trivia)) &&
        (puntajeAcumuladoT trivia noG) > (puntajeAcumuladoT trivia usuario)
               
indice:: Eq a => a -> [a] -> Int
indice u (x:xs) | u==x = 0
                | otherwise = 1 + indice u xs

-- Fin posicionEnT -- 

-- palabrasRecurrentesT --

palabrasRecurrentesT :: Trivia -> Int -> [String]
palabrasRecurrentesT trivia n = sacarRepetidos(lasMasRecurrentes 
        ( masLargasQueNDeTrivia trivia n ) ( masLargasQueNDeTrivia trivia n ))

lasMasRecurrentes :: [String] -> [String] -> [String]
lasMasRecurrentes [] _ = []  
lasMasRecurrentes (x:xs) ys 
        | (apareceMasQueTodosLosDemas x ys ys) = (x : (lasMasRecurrentes xs ys))
        | otherwise = lasMasRecurrentes xs ys

                                                 
apareceMasQueTodosLosDemas :: Eq a => a ->[a] ->[a] -> Bool
apareceMasQueTodosLosDemas _ [] _ = True
apareceMasQueTodosLosDemas a (x:xs) ys = (cantApariciones a ys >= cantApariciones x ys) 
        && apareceMasQueTodosLosDemas a xs ys
                                                                                  
cantApariciones:: Eq a => a -> [a] -> Int
cantApariciones _ [] = 0
cantApariciones x (y:ys) |x==y = 1 + (cantApariciones x ys)
                         |otherwise = cantApariciones x ys 

masLargasQueNDeTrivia :: Trivia -> Int -> [String]               
masLargasQueNDeTrivia trivia n = masLargasQueN
        (palabrasDePregConRes (preguntasT trivia)) n

masLargasQueN :: [String] -> Int -> [String]
masLargasQueN [] _ = []
masLargasQueN (x:xs) n | length x < n = masLargasQueN xs n
                       | otherwise = x: (masLargasQueN xs n)

palabrasDePregConRes :: [Pregunta] -> [String]
palabrasDePregConRes [] = []
palabrasDePregConRes (p:ps) = palabras(textoP p) ++ palabras(rtaCorrectaP p) 
        ++ palabrasDePregConRes ps

-- Fin palabras recurrentes --
